﻿module ParsingTests


open System
open Microsoft.VisualStudio.TestTools.UnitTesting
open Utility
open Streams
open Tokens
open Steps
open ParsingEvents
open Parsing


[<TestClass>]
type public ParsingTests() = 

   [<TestMethod>]
   member public self.ParseStep_ReturnsFalseAndFiresNoEventsWithInvalidInput() =
      use stream = CreateStream("abcd efg hijk lmnop")
      use reader = CreateReader(stream)

      let context = new ParsingContext()
      let error = ref ""

      context.OnStepStarted.Add(fun (a) -> Assert.Fail())
      context.OnStepEnded.Add(fun (a) -> Assert.Fail())
      context.OnParsingError.Add(fun (e) -> error := e.Error.Message)

      let actual = ParseStep(StepKind.Given, reader, context)

      Assert.IsFalse(actual)
      Assert.AreEqual("Step 'Given' not found", !error)


   [<TestMethod>]
   member public self.ParseStep_ReturnsTrueAndFiresAllEventsWithValidInput() =
      use stream = CreateStream("Given: this is a step yo")
      use reader = CreateReader(stream)

      let context = new ParsingContext()
      let events = ref 0 
      
      context.OnStepStarted.Add(fun (a) -> events := 1)
      context.OnStepEnded.Add(fun (a) -> events := 2)

      let actual = ParseStep(StepKind.Given, reader, context)

      Assert.IsTrue(actual)
      Assert.AreEqual(2, !events)


   [<TestMethod>]
   member public self.ParseStep_TriggersParsingErrorEventOnException() =
      use stream = CreateStream("Given: this is a step yo")
      use reader = CreateReader(stream)

      let context = new ParsingContext()
      let error = ref false

      context.OnStepStarted.Add(fun (a) -> failwith "oops")
      context.OnParsingError.Add(fun (e) -> error := true)
      
      let actual = ParseStep(StepKind.Given, reader, context)

      Assert.IsFalse(actual)
      Assert.IsTrue(!error)


   [<TestMethod>]
   member public self.ParseScenario_ReturnsTrueAndFiresAllEventsWithValidInput() =
      use stream = CreateStream("
            Scenario: test scenario #1

               Given: a few certain things
                When: stuff happens
                Then: things are different
            ")
      use reader = CreateReader(stream)

      let context = new ParsingContext()
      let events = ref 0
      let texts = ref List.empty<string>
      
      context.OnScenarioStarted.Add(fun (a) -> events := !events + 1; texts := !texts @ [a.Section.Description.Source])
      context.OnScenarioEnded.Add(fun (a) -> events := !events + 1)
      context.OnStepStarted.Add(fun (a) -> events := !events + 1; texts := !texts @ [a.Section.Instructions |> ToString])
      context.OnStepEnded.Add(fun (a) -> events := !events + 1)
      context.OnParsingError.Add(fun (e) -> events := !events + 1)
      
      let actual = ParseScenario(reader, context)

      Assert.IsTrue(actual)
      Assert.AreEqual(8, !events)
      Assert.AreEqual("test scenario #1", (!texts).[0])
      Assert.AreEqual("a few certain things", (!texts).[1])
      Assert.AreEqual("stuff happens", (!texts).[2])
      Assert.AreEqual("things are different", (!texts).[3])

   [<TestMethod>]
   member public self.ParseFeature_ReturnsTrueAndFiresAllEventsWithValidInput() =
      use stream = CreateStream("
             Feature: this is feature #1

            Scenario: test scenario #1

               Given: a few certain things
                When: stuff happens
                Then: things are different

            Scenario: test scenario #2

               Given: a few certain things
                When: stuff happens
                Then: things are different
            ")
      use reader = CreateReader(stream)

      let context = new ParsingContext()
      let features = ref 0
      let scenarios = ref 0
      let error = ref false

      context.OnFeatureStarted.Add(fun (f) -> features := !features + 1)
      context.OnScenarioStarted.Add(fun (s) -> scenarios := !scenarios + 1)
      context.OnParsingError.Add(fun (e) -> error := true)

      let actual = ParseFeature(reader, context)

      Assert.IsTrue(actual)
      Assert.IsFalse(!error)
      Assert.AreEqual(1, !features)
      Assert.AreEqual(2, !scenarios)

   
   [<TestMethod>]
   member public self.ParseReader_ReturnsTrueAndFiresAllEventsWithValidInput() =
      use stream = CreateStream("
             Feature: this is feature #1

            Scenario: test scenario #1

               Given: a few certain things
                When: stuff happens
                Then: things are different

            Scenario: test scenario #2

               Given: a few certain things
                When: stuff happens
                Then: things are different

             Feature: this is feature #2

            Scenario: test scenario #3

               Given: a few certain things
                When: stuff happens
                Then: things are different

            Scenario: test scenario #4

               Given: a few certain things
                When: stuff happens
                Then: things are different
            ")
      use reader = CreateReader(stream)

      let context = new ParsingContext()
      let features = ref 0
      let scenarios = ref 0
      let error = ref false

      context.OnFeatureStarted.Add(fun (f) -> features := !features + 1)
      context.OnScenarioStarted.Add(fun (s) -> scenarios := !scenarios + 1)
      context.OnParsingError.Add(fun (e) -> error := true)

      ParseReader(reader, context)

      Assert.IsFalse(!error)
      Assert.AreEqual(2, !features)
      Assert.AreEqual(4, !scenarios)

